home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Libraries / C Internet Config / IC Component Source ƒ / IC Resource ƒ / IC Link In.c < prev    next >
Encoding:
Text File  |  1995-12-06  |  37.0 KB  |  951 lines  |  [TEXT/SPM ]

  1. /*
  2.     IC Link In.c
  3.     
  4.     Main code for accessing the configuration file.  This code can be linked in to an application
  5.     (if the component is not available) to provide access to the IC prefs file.
  6.     
  7.     This code represents the lowest-level of access to the config file.
  8.     
  9.     History
  10.         11/06/95 dhn - Started C port.
  11. */
  12.  
  13. /*
  14.     Original pascal comment:
  15.     
  16.         (* File:         ICLinkIn.p
  17.          * Generated by: 1.0d4
  18.          * For:          IC 1.2
  19.          * On:           Monday, 25 September 1995, 19:28:12
  20.          * 
  21.          * This file is part of the Internet Configuration system and
  22.          * is placed in the public domain for the benefit of all.
  23.          *)
  24. */
  25.  
  26. #include <Components.h>
  27. #include <AppleTalk.h>
  28. #include <Folders.h>
  29. #include <Processes.h>
  30. #include <Errors.h>
  31. #include <AppleEvents.h>
  32. #include <LowMem.h>
  33.  
  34. #include "IC Types.h"
  35. #include "IC Keys.h"
  36.  
  37. #include "IC Resource API.h"
  38. #include "IC Link In Subs.h"
  39.  
  40. #define kICOurManufacturer    'JPQE'
  41. #define kRes_Code            'ICRP'
  42.  
  43. // Local Prototypes
  44. #ifdef __cplusplus
  45. extern "C" {
  46. #endif
  47.  
  48. OSErr ICFindFolder(short vRefNum,OSType folderType,Boolean createFolder,short* foundVRefNum,long* foundDirID);
  49. Boolean ICRCloseIfOpen(ICRRecordPtr inst);
  50. ICError ValidDirSpec(ICDirSpec* folder);
  51. OSErr FoundFile(ICDirSpec* folder,short ndx,FSSpec* found_file);
  52. Boolean ScanFolder(ICRRecordPtr inst,ICDirSpec* folder,FSSpecPtr found_file);
  53. OSErr FindPrefFolder(ICDirSpec* pref_fold);
  54. void SetSFCWD(ICRRecordPtr inst);
  55. ICError GetFile(ICRRecordPtr inst,FSSpecPtr fs);
  56. ICError PutFile(ICRRecord* inst,FSSpecPtr fs);
  57. short ICRPermToFSPerm(ICPerm perm);
  58. ICError ICRCheckInside(ICRRecord* inst);
  59. ICError ICRForceInside(ICRRecord* inst,ICPerm perm,Boolean* force_info);
  60. ICError ICRReleaseInside(ICRRecord* inst,Boolean force_info);
  61. Boolean __URL_SpecStartChar(char ch);
  62. Boolean __URL_SpecEndChar(char ch);
  63. ICError ExpandSelection(char* datap,long len,long* selStart,long* selEnd);
  64. Boolean SpaceTab(char ch);
  65. Boolean SpaceTabRet(char ch);
  66. ICError ShrinkSelection(char* datap,long len,long* selStart,long* selEnd);
  67. ICError StripReturns(Handle urlh);
  68. void Unpah=(Handle)0;
  69.             }
  70.             if (prefh==(Handle)0)
  71.                 old_attr=0;
  72.             else
  73.                 old_attr=**((long**)prefh);
  74.             
  75.             if (attr==ICattr_no_change)
  76.                 attr=old_attr;
  77.             
  78.             if ((old_attr&ICattr_locked_mask)&&(attr&ICattr_locked_mask)&&(buf!=(Ptr)0))
  79.                 err=icPermErr;
  80.             
  81.             if (prefh==(Handle)0){
  82.                 prefh=NewHandle(size+4);
  83.                 err=MemError();
  84.                 
  85.                 if (err==noErr){
  86.                     do {
  87.                         id=Unique1ID(kRes_Code);
  88.                     } while (id<=127);
  89.                     
  90.                     AddResource(prefh,kRes_Code,id,key);
  91.                     err=ResError();
  92.                     
  93.                     if (err!=noErr){
  94.                         DisposeHandle(prefh);
  95.                         prefh=(Handle)0;
  96.                     }
  97.                 }
  98.             }
  99.             if ((err==noErr)&&(buf!=(Ptr)0)){
  100.                 SetHandleSize(prefh,size+4);
  101.                 err=MemError();
  102.             }
  103.             if ((err==noErr)&&(size>0))
  104.                 BlockMoveData(buf,(Ptr)((*prefh)+4),size);
  105.             if (err==noErr){
  106.                 **((long**)prefh)=attr;
  107.                 ChangedResource(prefh);
  108.                 WriteResource(prefh);
  109.                 err=ResError();
  110.             }
  111.             UseResFile(old_refnum);
  112.         }
  113.     }
  114.     
  115.     if (prefh!=(Handle)0)
  116.         ReleaseResource(prefh);
  117.     
  118.     err2=ICRReleaseInside(inst,force_info);
  119.     
  120.     if (err==noErr)
  121.         err=err2;
  122.     
  123.     return err;
  124. }
  125.  
  126. // I call ICRForceInside to speed this routine up.  ICRForceInside will do an ICRBegin and hence open the resource
  127. // file, which is good because otherwise I'd open it twice, once for each ICRGetPref.
  128.  
  129. ICError ICRFindPrefHandle(ICRRecord* inst,StringPtr key,ICAttr* attr,Handle prefh){
  130.     ICError err=noErr,err2=noErr;
  131.     long prefsize=0L;
  132.     Boolean force_info;
  133.     
  134.     if (prefh==(Handle)0)
  135.         err=paramErr;
  136.     
  137.     if (err==noErr){
  138.         err=ICRForceInside(inst,icReadOnlyPerm,&force_info);
  139.         if (err==noErr)
  140.             err=ICRGetPref(inst,key,attr,(Ptr)0,&prefsize);
  141.         
  142.         if (err==noErr){
  143.             SetHandleSize(prefh,prefsize);
  144.             err=MemError();
  145.         }
  146.         
  147.         if (err==noErr){
  148.             HLock(prefh);
  149.             err=ICRGetPref(inst,key,attr,*prefh,&prefsize);
  150.             HUnlock(prefh);
  151.         }
  152.         
  153.         err2=ICRReleaseInside(inst,force_info);
  154.     }
  155.     if (err==noErr)
  156.         err=err2;
  157.     
  158.     if ((prefh!=(Handle)0)&&(err!=noErr)){
  159.         SetHandleSize(prefh,0);
  160.     }
  161.     
  162.     return err;
  163. }
  164.  
  165. ICError ICRGetPrefHandle(ICRRecord* inst,StringPtr key,ICAttr* attr,Handle* prefh){
  166.     ICError err;
  167.     
  168.     *prefh=NewHandle(0);
  169.     err=MemError();
  170.     
  171.     if (err==noErr)
  172.         err=ICRFindPrefHandle(inst,key,attr,*prefh);
  173.     
  174.     if (err==icPrefNotFoundErr){
  175.         SetHandleSize(*prefh,0);
  176.         *attr=0;
  177.         err=noErr;
  178.     }
  179.     
  180.     return err;
  181. }
  182.  
  183. ICError ICRSetPrefHandle(ICRRecord* inst,StringPtr key,ICAttr attr,Handle prefh){
  184.     ICError err=noErr;
  185.     SignedByte s;
  186.     
  187.     if (prefh!=(Handle)0){
  188.         if (*prefh==(Ptr)0)
  189.             err=paramErr;
  190.         if (err==noErr){
  191.             s=HGetState(prefh);
  192.             HLock(prefh);
  193.             err=ICRSetPref(inst,key,attr,*prefh,GetHandleSize(prefh));
  194.             HSetState(prefh,s);
  195.         }
  196.     } else {
  197.         err=ICRSetPref(inst,key,attr,(Ptr)0,0);
  198.     }
  199.     
  200.     return err;
  201. }
  202.  
  203. ICError ICRCountPref(ICRRecord* inst,long* count){
  204.     ICError err;
  205.     short old_refnum;
  206.     
  207.     err=ICRCheckInside(inst);
  208.     if (err==noErr){
  209.         if (inst->config_refnum==0)
  210.             *count=0;
  211.         else {
  212.             old_refnum=CurResFile();
  213.             UseResFile(inst->config_refnum);
  214.             err=ResError();
  215.             if (err==noErr){
  216.                 *count=Count1Resources(kRes_Code);
  217.                 err=ResError();
  218.                 UseResFile(old_refnum);
  219.             }
  220.         }
  221.     }
  222.     
  223.     if (err!=noErr)
  224.         *count=0;
  225.     
  226.     return err;
  227. }
  228.  
  229. ICError ICRGetIndPref(ICRRecord* inst,long n,StringPtr key){
  230.     ICError err;
  231.     short old_refnum;
  232.     Handle prefh=(Handle)0;
  233.     short junk_id;
  234.     ResType junk_type;
  235.     
  236.     err=ICRCheckInside(inst);
  237.     if ((err==noErr)&&(n<1))
  238.         err=paramErr;
  239.     
  240.     if (err==noErr){
  241.         if (inst->config_refnum==0)
  242.             err=icPrefNotFoundErr;
  243.         else {
  244.             old_refnum=CurResFile();
  245.             UseResFile(inst->config_refnum);
  246.             err=ResError();
  247.             if (err==noErr){
  248.                 SetResLoad(false);
  249.                 prefh=Get1IndResource(kRes_Code,n);
  250.                 SetResLoad(true);
  251.                 
  252.                 if (prefh==(Handle)0)
  253.                     err=icPrefNotFoundErr;
  254.                 else {
  255.                     GetResInfo(prefh,&junk_id,&junk_type,key);
  256.                     err=ResError();
  257.                 }
  258.                 UseResFile(old_refnum);
  259.             }
  260.         }
  261.     }
  262.     
  263.     if (prefh!=(Handle)0)
  264.         ReleaseResource(prefh);
  265.     
  266.     return err;
  267. }
  268.  
  269. ICError ICRDeletePref(ICRRecord* inst,StringPtr key){
  270.     ICError err;
  271.     Handle prefh;
  272.     short old_refnum;
  273.     
  274.     err=ICRCheckInside(inst);
  275.     if ((err==noErr)&&(key[0]==0))
  276.         err=paramErr;
  277.     
  278.     if (err==noErr){
  279.         if (inst->config_refnum==0)
  280.             err=icPrefNotFoundErr;
  281.         else {
  282.             old_refnum=CurResFile();
  283.             UseResFile(inst->config_refnum);
  284.             err=ResError();
  285.             if (err==noErr){
  286.                 SetResLoad(false);
  287.                 prefh=Get1NamedResource(kRes_Code,key);
  288.                 err=ResError();
  289.                 SetResLoad(true);
  290.                 if (prefh==(Handle)0)
  291.                     err=icPrefNotFoundErr;
  292.                 else {
  293.                     RmveResource(prefh);
  294.                     DisposeHandle(prefh);
  295.                     err=ResError();
  296.                 }
  297.                 UseResFile(old_refnum);
  298.             }
  299.         }
  300.     }
  301.     
  302.     return err;
  303. }
  304.  
  305. ICError ICREnd(ICRRecord* inst){
  306.     ICError err;
  307.     
  308.     err=ICRCheckInside(inst);
  309.     ICRCloseIfOpen(inst);
  310.     
  311.     return err;
  312. }
  313.  
  314. ICError ICRDefaultFileName(ICRRecord* inst,StringPtr name){
  315.     Str63 lname=kICDefaultFileName;
  316.     
  317.     BlockMoveData(lname,name,lname[0]+1);
  318.     
  319.     return noErr;
  320. }
  321.  
  322. ICError ICREditPreferences(ICRRecord* inst,StringPtr key){
  323.     ICError err;
  324.     
  325.     if (!inst->have_config_file)
  326.         return bdNamErr;
  327.     
  328.     return EditPreferences(key,&(inst->config_file));
  329. }
  330.  
  331. /*
  332.     URL Parsing Algorithm
  333.  
  334.     1. if there is a selection skip to step 4
  335.     2. expand selection to end of word (never skip an angle bracket though)
  336.     3. if either end has an angle bracket then expand other end to search for angle bracket
  337.     4. strip trailing and leading whitespace
  338.     5. strip whitespace CR whitespace
  339.     6. off < > if necessary
  340.     7. remove leading URL:
  341.     8. extract protocol by looking forwards for :
  342.     9. if no protocol then prepend "hint:"
  343. */
  344.  
  345. Boolean __URL_SpecStartChar(char ch){
  346.     switch (ch){
  347.         case ' ':
  348.         case '<':
  349.         case 9:
  350.         case 13:
  351.             return true;
  352.         default:
  353.             return false;
  354.     }
  355. }
  356.  
  357. Boolean __URL_SpecEndChar(char ch){
  358.     switch (ch){
  359.         case ' ':
  360.         case '>':
  361.         case 9:
  362.         case 13:
  363.             return true;
  364.         default:
  365.             return false;
  366.     }
  367. }
  368.  
  369. ICError ExpandSelection(char* datap,long len,long* selStart,long* selEnd){
  370.     ICError err=noErr;
  371.     Boolean found;
  372.     
  373.     // expand leading selection backwards looking for word break
  374.     while ((*selStart>0)&&(!__URL_SpecStartChar(datap[(*selStart)-1])))
  375.         (*selStart)--;
  376.     if ((*selStart>0)&&(datap[(*selStart)-1]=='<'))
  377.         (*selStart)--;
  378.     
  379.     // expand trailing selection forwards looking for word break
  380.     while ((*selEnd<len)&&(!__URL_SpecEndChar(datap[*selEnd])))
  381.         (*selEnd)++;
  382.     if ((*selEnd<len)&&(datap[*selEnd]=='>'))
  383.         (*selEnd)++;
  384.     
  385.     // if first char was a < then expand trailing selection to meet matching >
  386.     if ((datap[*selStart]=='<')&&(datap[(*selEnd)-1]!='>')){
  387.         while ((datap[(*selEnd)-1]!='>')&&((*selEnd)-1<=len))
  388.             (*selEnd)++;
  389.         
  390.         // now either a match or at end of len
  391.         if (datap[(*selEnd)-1]!='>')
  392.             return icNoURLErr;
  393.     }
  394.     
  395.     // if last char was a > then expand leading selection to meet matching <
  396.     if ((datap[*selEnd]=='>')&&(datap[*selStart]!='<')){
  397.         while ((datap[*selStart]!='<')&&(*selStart>=0))
  398.             (*selStart)--;
  399.         
  400.         // now either a match or at end of len
  401.         if (datap[*selStart]!='<')
  402.             return icNoURLErr;
  403.     }
  404.     
  405.     return err;
  406. }
  407.  
  408. Boolean SpaceTab(char ch){
  409.     if ((ch==' ')||(ch==9))
  410.         return true;
  411.     return false;
  412. }
  413.  
  414. Boolean SpaceTabRet(char ch){
  415.     if (ch==13)
  416.         return true;
  417.     return SpaceTab(ch);
  418. }
  419.  
  420. ICError ShrinkSelection(char* datap,long len,long* selStart,long* selEnd){
  421.     if (SpaceTab(datap[*selStart]))
  422.         while (SpaceTab(datap[*selStart]))
  423.             (*selStart)++;
  424.     if (SpaceTab(datap[(*selEnd)-1]))
  425.         while (SpaceTab(datap[(*selEnd)-1]))
  426.             (*selEnd)--;
  427.     
  428.     return noErr;
  429. }
  430.  
  431. ICError StripReturns(Handle urlh){
  432.     ICError err;
  433.     long srcsize,srcndx,dstndx;
  434.     char* buf;
  435.     SignedByte s;
  436.     
  437.     srcsize=GetHandleSize(urlh);
  438.     err=MemError();
  439.     if (srcsize==0){
  440.         if (err!=noErr)
  441.             return err;
  442.         
  443.         return icNoURLErr;
  444.     }
  445.     
  446.     srcndx=0;
  447.     dstndx=0;
  448.     
  449.     s=HGetState(urlh);
  450.     HLock(urlh);
  451.     buf=(char*)(*urlh);
  452.     
  453.     // skip down the buffer copying src to dst except when meeting cr
  454.     while (srcndx<srcsize){
  455.         if (buf[srcndx]==13){
  456.             // move dstndx back to point to previous non-whitespace
  457.             while ((dstndx>0)&&(SpaceTab(buf[dstndx-1])))
  458.                 dstndx--;
  459.             // move srcndx forwards to next non-whitespace
  460.             while ((srcndx<srcsize)&&(SpaceTabRet(buf[srcndx])))
  461.                 srcndx++;
  462.         }
  463.         
  464.         if (srcndx<srcsize){
  465.             // copy byte from src to dest
  466.             buf[dstndx]=buf[srcndx];
  467.             srcndx++;
  468.             dstndx++;
  469.         }
  470.     }
  471.     
  472.     HSetState(urlh,s);
  473.     
  474.     // resize the handle to the number of bytes that we copied
  475.     SetHandleSize(urlh,dstndx);
  476.     err=MemError();
  477.     
  478.     return err;
  479. }
  480.  
  481. ICError ICRParseURL(ICRRecord* inst,StringPtr hint,Ptr data,long len,long* selStart,long* selEnd,Handle urlh){
  482.     char* datap=(char*)data;
  483.     Str31 tmp="\pURL:";
  484.     long junklong;
  485.     long ndx;
  486.     ICError err=noErr;
  487.     
  488.     if ((data==(Ptr)0)||(urlh==(Handle)0)||(*urlh==(Ptr)0)||(len<=0)||(*selStart<0)||(*selEnd<0)||(*selStart>len)||(*selEnd>len)||(*selStart>*selEnd))
  489.         return paramErr;
  490.     
  491.     if (*selStart==*selEnd)
  492.         err=ExpandSelection(datap,len,selStart,selEnd);
  493.     if (err==noErr) // remove leading and trailing whitespace
  494.         err=ShrinkSelection(datap,len,selStart,selEnd);
  495.     
  496.     if ((err==noErr)&&(*selStart>=*selEnd))
  497.         return icNoURLErr;
  498.     
  499.     err=PtrToXHand((Ptr)&(datap[*selStart]),urlh,(*selEnd)-(*selStart));
  500.     if (err==noErr)
  501.         err=StripReturns(urlh);
  502.     
  503.     if (err==noErr){
  504.         // strip any enclosing < >
  505.         char* buf;
  506.         long bsize=GetHandleSize(urlh);
  507.         SignedByte s=HGetState(urlh);
  508.         Boolean doTrim=false;
  509.         
  510.         HLock(urlh);
  511.         buf=(char*)(*urlh);
  512.         
  513.         if ((buf[0]=='<')&&(buf[bsize-1]=='>')){
  514.             doTrim=true;
  515.         }
  516.         
  517.         HSetState(urlh,s);
  518.         
  519.         if (doTrim){
  520.             SetHandleSize(urlh,bsize-1);
  521.             HUnlock(urlh);
  522.             // unlock before the munger call
  523.             Munger(urlh,0,(Ptr)0,1,(Ptr)-1,0);
  524.             HSetState(urlh,s);
  525.         }
  526.         
  527.         // trim off leading "\pURL:"
  528.         HLock(urlh);
  529.         if ((GetHandleSize(urlh)>tmp[0])&&(IUMagIDString(*urlh,&(tmp[1]),tmp[0],tmp[0])==0)){
  530.             HUnlock(urlh);
  531.             Munger(urlh,0,(Ptr)0,tmp[0],(Ptr)-1,0);
  532.         }
  533.         HSetState(urlh,s);
  534.         
  535.         // search for protocol
  536.         tmp[0]=1;tmp[1]=':';
  537.         HUnlock(urlh);
  538.         ndx=Munger(urlh,0,&(tmp[1]),1,(Ptr)0,0);
  539.         if ((ndx<0)||(ndx>255)){
  540.             // failed to find a colon in first 256 bytes,prepend "hint:" to url
  541.             if (hint[0]==0)
  542.                 err=icNoURLErr;
  543.             else {
  544.                 Munger(urlh,0,(Ptr)0,0,&(hint[1]),hint[0]);
  545.                 err=MemError();
  546.             }
  547.         }
  548.         HSetState(urlh,s);
  549.     }
  550.     return err;
  551. }
  552.  
  553. ICError ICRLaunchURL(ICRRecord* inst,StringPtr hint,Ptr data,long len,long* selStart,long* selEnd){
  554.     ICError err;
  555.     Handle urlh;
  556.     ICAppSpec helper;
  557.     Str255 scheme;
  558.     Str255 temp=kICHelper;
  559.     long junk_attr;
  560.     long size;
  561.     
  562.     urlh=NewHandle(0);
  563.     err=MemError();
  564.     
  565.     if (err==noErr)
  566.         err=ICRParseURL(inst,hint,data,len,selStart,selEnd,urlh);
  567.     else 
  568.         urlh=(Handle)0;
  569.     
  570.     if (err==noErr)
  571.         err=FindScheme(urlh,scheme);
  572.     
  573.     if (err==noErr){
  574.         size=sizeof(ICAppSpec);
  575.         BlockMoveData(scheme,(Ptr)&(temp[temp[0]+1]),scheme[0]);
  576.         temp[0]+=scheme[0];
  577.         err=ICRGetPref(inst,temp,&junk_attr,(Ptr)(&helper),&size);
  578.     }
  579.     
  580.     if (err==noErr)
  581.         err=LaunchURL(helper.fCreator,urlh);
  582.     
  583.     if (urlh!=(Handle)0)
  584.         DisposeHandle(urlh);
  585.     
  586.     return err;
  587. }
  588.  
  589. void UnpackCopyString(Ptr* p,StringPtr s){
  590.     short len;
  591.     
  592.     // calc the len of the current pascal string pointed to by p
  593.     len=((**p) & 0x00ff) +1;
  594.     
  595.     // copy the string in the buffer to s
  596.     BlockMoveData(*p,s,len);
  597.     
  598.     // move the pointer to the start of the next pascal string
  599.     *p=(Ptr)((*p)+len);
  600. }
  601.  
  602. // Internal Mapping Subs
  603. OSErr UnpackEntry(Handle entries,long pos,ICMapEntry* entry,long* user_length){
  604.     // WARNING: Depends very much on the exact format of ICMapEntry!
  605.     Ptr org,p;
  606.     long maxsize;
  607.     OSErr err=noErr;
  608.     
  609.     if ((entries==(Handle)0)||(*entries==(Ptr)0)||(pos<0)||(pos>GetHandleSize(entries)-6))
  610.         return paramErr;
  611.     
  612.     p=(Ptr)((*entries)+pos);
  613.     maxsize=GetHandleSize(entries);
  614.     org=p;
  615.     
  616.     BlockMoveData(p,(Ptr)entry,6);
  617.     
  618.     if ((entry->fixed_length!=ICmap_fixed_length)||(entry->fixed_length>entry->total_length)||(entry->total_length>maxsize))
  619.         return badExtResource;
  620.     
  621.     BlockMoveData(p,entry,entry->fixed_length);
  622.     p=(Ptr)(p+entry->fixed_length);
  623.     UnpackCopyString(&p,entry->extension);
  624.     UnpackCopyString(&p,entry->creator_app_name);
  625.     UnpackCopyString(&p,entry->post_app_name);
  626.     UnpackCopyString(&p,entry->MIME_type);
  627.     UnpackCopyString(&p,entry->entry_name);
  628.     
  629.     *user_length=entry->total_length-(p-org);
  630.     
  631.     return err;
  632. }
  633.  
  634. // a fast version of ICRGetEntry doesn't return all of the strings for the entry
  635. // WARNING: Depends very much on the exact format of ICMapEntry!
  636. OSErr FastGetEntry(Handle entries,long pos,ICMapEntry* entry){
  637.     Ptr org,p;
  638.     long maxsize;
  639.     OSErr err=noErr;
  640.     
  641.     if ((entries==(Handle)0)||(*entries==(Ptr)0)||(pos<0)||(pos>GetHandleSize(entries)-6))
  642.         return paramErr;
  643.     
  644.     p=(Ptr)((*entries)+pos);
  645.     maxsize=GetHandleSize(entries);
  646.     BlockMoveData(p,entry,6);
  647.     
  648.     if ((entry->fixed_length!=ICmap_fixed_length)||(entry->fixed_length>entry->total_length)||(entry->total_length>maxsize))
  649.         return badExtResource;
  650.     
  651.     BlockMoveData(p,entry,entry->fixed_length);
  652.     p=(Ptr)(p+entry->fixed_length);
  653.     BlockMoveData(p,entry->extension,(((*p)&0x00ff)+1));
  654.     return err;
  655. }
  656.  
  657. void PackCopyString(ICMapEntry* entry,Ptr p,StringPtr s){
  658.     
  659.     BlockMoveData(s,(Ptr)(p+entry->total_length),s[0]+1);
  660.     entry->total_length+=s[0]+1;
  661. }
  662.  
  663. void PackEntry(ICMapEntry* entry,Ptr p,long user_length){
  664.     Ptr a,b;
  665.     
  666.     entry->version=0;
  667.     
  668.     a=(Ptr)&(entry->extension);
  669.     b=(Ptr)entry;
  670.     
  671.     entry->fixed_length=a-b;
  672.     entry->total_length=entry->fixed_length;
  673.     
  674.     PackCopyString(entry,p,entry->extension);
  675.     PackCopyString(entry,p,entry->creator_app_name);
  676.     PackCopyString(entry,p,entry->post_app_name);
  677.     PackCopyString(entry,p,entry->MIME_type);
  678.     PackCopyString(entry,p,entry->entry_name);
  679.     
  680.     entry->total_length+=user_length;
  681.     
  682.     BlockMoveData(entry,p,entry->fixed_length);
  683. }
  684.  
  685. short GetShort(Ptr P){
  686.     unsigned char* p=(unsigned char*)P;
  687.     short val=0;
  688.     
  689.     val=p[0];
  690.     val <<= 8;
  691.     val+=p[1];
  692.     
  693.     return val;
  694. }
  695.  
  696. char UpCase(char ch){
  697.     
  698.     if ((ch>='a')&&(ch<='z'))
  699.         return (ch-'a')+'A';
  700.     
  701.     return ch;
  702. }
  703.  
  704. Boolean IsExtensionVar(StringPtr name,StringPtr ext){
  705.     short pn,pe;
  706.     
  707.     if (name[0]>=ext[0]){
  708.         pn=name[0]-ext[0]+1;
  709.         pe=1;
  710.         
  711.         while (pe<=ext[0]){
  712.             if (UpCase(name[pn])!=UpCase(ext[pe]))
  713.                 break;
  714.             
  715.             pn++;
  716.             pe++;
  717.         }
  718.         
  719.         return pe>ext[0];
  720.     }
  721.     return false;
  722. }
  723.  
  724. // Low Level Mapping Routines
  725.  
  726. ICError ICRCountMapEntries(ICRRecord* inst,Handle entries,long* count){
  727.     Ptr p;
  728.     long pos;
  729.     short size;
  730.     long hsize;
  731.     
  732.     if ((entries==(Handle)0)||(*entries==(Ptr)0))
  733.         return paramErr;
  734.     
  735.     p=*entries;
  736.     pos=0L;
  737.     *count=0;
  738.     hsize=GetHandleSize(entries);
  739.     while (pos<hsize){
  740.         size=GetShort(p); // extract the total_length value from the current pointer
  741.         pos+=size; // add it to the pos offset
  742.         p+=size; // add it to the pointer
  743.         (*count)++; // increment the count
  744.     }
  745.     
  746.     return noErr;
  747. }
  748.  
  749. ICError ICRGetIndMapEntry(ICRRecord* inst,Handle entries,long ndx,long* pos,ICMapEntry* entry){
  750.     ICError err;
  751.     Ptr p;
  752.     long i;
  753.     short size;
  754.     long hsize;
  755.     
  756.     if ((entries==(Handle)0)||(*entries==(Ptr)0)||(ndx<0))
  757.         return paramErr;
  758.     
  759.     p=(Ptr)*entries;
  760.     *pos=0;
  761.     hsize=GetHandleSize(entries);
  762.     
  763.     while ((ndx>1)&&(*pos<hsize)){
  764.         size=GetShort(p); // extract the total_length value from the current pointer
  765.         *pos+=size; // add the size to the pos offset
  766.         p+=size; // add the size to the pointer
  767.         ndx--; // decrease the index for the entry
  768.     }
  769.     
  770.     return ICRGetMapEntry(inst,entries,*pos,entry);
  771. }
  772.  
  773. ICError ICRGetMapEntry(ICRRecord* inst,Handle entries,long pos,ICMapEntry* entry){
  774.     ICError err;
  775.     long user_length;
  776.     
  777.     if ((entries==(Handle)0)||(*entries==(Ptr)0)||(pos<0)||(pos>GetHandleSize(entries)))
  778.         return paramErr;
  779.     
  780.     return UnpackEntry(entries,pos,entry,&user_length);
  781. }
  782.  
  783. ICError ICRSetMapEntry(ICRRecord* inst,Handle entries,long pos,ICMapEntry* entry){
  784.     ICError err;
  785.     ICMapEntry e,oldentry;
  786.     long user_length,source_length;
  787.     
  788.     if ((entries==(Handle)0)||(*entries==(Ptr)0)||(pos<0)||(pos>GetHandleSize(entries)))
  789.         return paramErr;
  790.     
  791.     err=UnpackEntry(entries,pos,&oldentry,&user_length);
  792.     
  793.     if (err==noErr){
  794.         PackEntry(entry,(Ptr)&e,user_length);
  795.         source_length=oldentry.total_length-user_length;
  796.         
  797.         if (user_length<8){ // hack to remove alignment bytes from previous version
  798.             source_length=oldentry.total_length;
  799.             e.total_length=e.total_length-user_length;
  800.             user_length=0;
  801.         }
  802.         Munger(entries,pos,(Ptr)0,source_length,&e,e.total_length-user_length);
  803.         err=MemError();
  804.     }
  805.     
  806.     return err;
  807. }
  808.  
  809. ICError ICRDeleteMapEntry(ICRRecord* inst,Handle entries,long pos){
  810.     ICError err;
  811.     ICMapEntry entry;
  812.     long user_length;
  813.     
  814.     if ((entries==(Handle)0)||(*entries==(Ptr)0)||(pos<0)||(pos>=GetHandleSize(entries)))
  815.         return paramErr;
  816.     
  817.     err=UnpackEntry(entries,pos,&entry,&user_length);
  818.     
  819.     if (err==noErr){
  820.         Munger(entries,pos,(Ptr)0,entry.total_length,(Ptr)-1,0);
  821.         err=MemError();
  822.     }
  823.     
  824.     return err;
  825. }
  826.  
  827. ICError ICRAddMapEntry(ICRRecord* inst,Handle entries,ICMapEntry* entry){
  828.     ICError err;
  829.     ICMapEntry tmp_entry;
  830.     
  831.     if ((entries==(Handle)0)||(*entries==(Ptr)0))
  832.         return paramErr;
  833.     
  834.     PackEntry(entry,(Ptr)&tmp_entry,0);
  835.     
  836.     return PtrAndHand(&tmp_entry,entries,entry->total_length);
  837. }
  838.  
  839. // High Level Mapping Subs
  840.  
  841. ICError ICRMapEntriesFilename(ICRRecord* inst,Handle entries,StringPtr filename,ICMapEntry* entry){
  842.     // Implementation lifted directly from Space Aliens
  843.     ICError err;
  844.     short longest_len;
  845.     long posndx,found_pos;
  846.     
  847.     if ((entries==(Handle)0)||(*entries==(Ptr)0)||(filename[0]==0))
  848.         return paramErr;
  849.     
  850.     // loop through the entries
  851.     // looking for the longest match
  852.     
  853.     longest_len=0;
  854.     posndx=0;
  855.     
  856.     while (FastGetEntry(entries,posndx,entry)==noErr){
  857.         // the entry matches if not_incoming flag bit is clear,
  858.         // it's longer than the previous match, it's longer than the filename,
  859.         // and it matches the last N chars of the filename.
  860.         
  861.         if ((entry->extension[0]>longest_len)&&(!(entry->flags&ICmap_not_incoming_mask))&&(IsExtensionVar(filename,entry->extension))){
  862.             // record the new longest entry
  863.             found_pos=posndx;
  864.             longest_len=entry->extension[0];
  865.         }
  866.         // increment posndx so that we get the next entry the next time around the loop
  867.         posndx+=entry->total_length;
  868.     }
  869.     
  870.     if (longest_len==0)
  871.         return icPrefNotFoundErr;
  872.     
  873.     return ICRGetMapEntry(inst,entries,found_pos,entry);
  874. }
  875.  
  876. ICError ICRMapEntriesTypeCreator(ICRRecord* inst,Handle entries,OSType fType,OSType fCreator,StringPtr filename,ICMapEntry* entry){
  877.     ICError err;
  878.     long posndx,found_pos,match_weight,best_weight;
  879.     
  880.     if ((entries==(Handle)0)||(*entries==(Ptr)0))
  881.         return paramErr;
  882.     
  883.     posndx=0L;
  884.     best_weight=-1L;
  885.     
  886.     while (FastGetEntry(entries,posndx,entry)==noErr){
  887.         if (!(entry->flags&ICmap_not_outgoing_mask)){
  888.             if (entry->file_type==fType){
  889.                 match_weight=entry->file_creator==fCreator;
  890.                 if (IsExtensionVar(filename,entry->extension)){
  891.                     match_weight+=2*(entry->extension[0]);
  892.                 }
  893.                 if (match_weight>best_weight){
  894.                     // record the new longest entry
  895.                     found_pos=posndx;
  896.                     best_weight=match_weight;
  897.                 }
  898.             }
  899.         }
  900.         posndx+=entry->total_length;
  901.     }
  902.     
  903.     if (best_weight==-1)
  904.         return icPrefNotFoundErr;
  905.     
  906.     return ICRGetMapEntry(inst,entries,found_pos,entry);
  907. }
  908.  
  909. // High Level Mapping Routines
  910.  
  911. ICError ICRMapFilename(ICRRecord* inst,StringPtr filename,ICMapEntry* entry){
  912.     ICError err;
  913.     Handle entries;
  914.     ICAttr junk_attr;
  915.     
  916.     if (filename[0]==0)
  917.         return paramErr;
  918.     
  919.     err=ICRGetPrefHandle(inst,kICMapping,&junk_attr,&entries);
  920.     if (err==noErr){
  921.         err=ICRMapEntriesFilename(inst,entries,filename,entry);
  922.         DisposeHandle(entries);
  923.     }
  924.     
  925.     return err;
  926. }
  927.  
  928. ICError ICRMapTypeCreator(ICRRecord* inst,OSType fType,OSType fCreator,StringPtr filename,ICMapEntry* entry){
  929.     ICError err;
  930.     Handle entries;
  931.     ICAttr junk_attr;
  932.     
  933.     err=ICRGetPrefHandle(inst,kICMapping,&junk_attr,&entries);
  934.     if (err==noErr){
  935.         err=ICRMapEntriesTypeCreator(inst,entries,fType,fCreator,filename,entry);
  936.         DisposeHandle(entries);
  937.     }
  938.     
  939.     return err;
  940. }
  941.  
  942.  
  943.  
  944.  
  945.  
  946.  
  947.  
  948.  
  949.  
  950.  
  951.